<?php

namespace app\components\lib;

use app\components\CTools;
use app\components\factory\MessageFactory;

class CWechat
{


    //==================多开凭证
    public $wechat_uuid;
    public $session, $user_agent, $cookie, $webkit;
    public $sessionKeys = [], $deviceID, $scanTime;
    public $syncKey, $syncKeyStr;
    public $myself;
    public $member_users, $group_users, $group_users_sync, $public_users, $system_users;

    //username 与 pinyin 对应关系
    public $usernameMapPinyinList;

    public $startTime, $rebootType;


    public function __construct($session, $startType = "start")
    {

        $this->deviceID = $this->sessionKeys['deviceID'] = 'e' . substr(md5(uniqid()), 2, 15);
        $this->session = $session;
        $this->user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.109 Safari/537.36';

        $this->cookie = \Yii::$app->basePath . "/runtime/wechat/cookie/cookie." . $session;
        $this->webkit = [
            'cookie' => $this->cookie,
            'user_agent' => $this->user_agent
        ];
        $this->startTime = time();
        $this->rebootType = $startType;


    }


    public function syncSessions()
    {
        $cache = \Yii::$app->cache;
        $key = "WECHAT_SESSION_" . $this->session;
        $sessionKeys = $cache->get($key);
        #不存在或者已过期
        if ($sessionKeys == false || $this->rebootType == "restart") {
            $this->_clearCookie($this->cookie);
            $this->firstInitUuid();
            #二维码
            QrcodeTool::cmdqrcode($this->wechat_uuid);
            $this->firstWaitForLogin();
            $this->firstStartLogin();
            $cache->set($key, $this->sessionKeys, \Yii::$app->params['sessionKeepTime']);
        } else {
            #已存在
            $this->sessionKeys = $sessionKeys;
            $cache = \Yii::$app->cache;
            $this->scanTime = $cache->get("WECHAT_SESSION_SCAN_TIME" . $this->session);
        }

    }


    public function firstInitUuid()
    {

        $url = 'https://login.wx.qq.com/jslogin';
        $params = [
            'appid' => "wx782c26e4c19acffb",
            'fun' => 'new',
            'lang' => "zh_CN",
            '_' => time(),
        ];
        $data = CHttpWechat::curlGet($url, $this->webkit, $params);
        $regx = '/window.QRLogin.code = (\d+); window.QRLogin.uuid = "(\S+?)"/';
        if (preg_match($regx, $data, $pm)) {
            $code = $pm[1];
            $this->wechat_uuid = $this->sessionKeys['wechat_uuid'] = $pm[2];
            return $code == '200';
        }
        return false;
    }


    public function firstWaitForLogin()
    {
        $retryTime = 10;#默认重试10次
        $tip = 1;

        while ($retryTime > 0) {
            $url = sprintf('https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?tip=%s&uuid=%s&_=%s', $tip, $this->wechat_uuid, time());
            $data = CHttpWechat::curlGet($url, $this->webkit);
            preg_match('/window.code=(\d+);/', $data, $pm);
            if (!empty($pm[1])) {
                $code = $pm[1];


                if ($code == '201') {
                    $tip = 0;
                    CTools::_echo("请点击确认按钮...");
                }

                if ($code == '200') {
                    CTools::_echo("扫码成功...");
                    preg_match('/window.redirect_uri="(https:\/\/(\S+?)\/\S+?)";/', $data, $matches);
                    $this->sessionKeys['redirect_url'] = $matches[1] . '&fun=new';
                    $url = 'https://%s/cgi-bin/mmwebwx-bin';
                    $this->sessionKeys['synccheck_url'] = sprintf("https://%s/cgi-bin/mmwebwx-bin", 'webpush.' . $matches[2]);
                    $this->sessionKeys['base_url_prefix'] = sprintf($url, $matches[2]);

                    #获取扫描时间
                    preg_match('/(.*)scan=(\d+)/', $data, $matches2);
                    $this->scanTime = $matches2[2];
                    $cache = \Yii::$app->cache;
                    $key = "WECHAT_SESSION_SCAN_TIME" . $this->session;
                    $cache->set($key, $this->scanTime, \Yii::$app->params['sessionKeepTime']);
                    return;
                }

                if ($code == '408') {
                    $tip = 1;
                    CTools::_echo("已超时...");
                }
            }
            $tip = 1;
            $retryTime -= 1;
            sleep(1);
        }
    }

    public function firstStartLogin()
    {
        $data = CHttpWechat::curlGet($this->sessionKeys['redirect_url'], $this->webkit);
        $array = (array)simplexml_load_string($data, 'SimpleXMLElement', LIBXML_NOCDATA);
        if (!isset($array['skey']) || !isset($array['wxsid']) || !isset($array['wxuin']) || !isset($array['pass_ticket'])) {
            return false;
        }

        $this->sessionKeys['Skey'] = $array['skey'];
        $this->sessionKeys['Sid'] = $array['wxsid'];
        $this->sessionKeys['Uin'] = $array['wxuin'];
        $this->sessionKeys['passTicket'] = $array['pass_ticket'];

        $this->sessionKeys['baseRequest'] = [
            'Uin' => $this->sessionKeys['Uin'],
            'Sid' => $this->sessionKeys['Sid'],
            'Skey' => $this->sessionKeys['Skey'],
            'DeviceID' => $this->sessionKeys['deviceID']
        ];

        return true;
    }

    /**
     * 初始化
     * @param bool|true $first
     * @return mixed
     */
    public function webwxinit($first = true)
    {
        $url = sprintf($this->sessionKeys['base_url_prefix'] . '/webwxinit?pass_ticket=%s&skey=%s&r=%s', $this->sessionKeys['passTicket'], $this->sessionKeys['Skey'], time());
        $params = [
            'BaseRequest' => $this->sessionKeys['baseRequest']
        ];
        $dic = CHttpWechat::curlPostJson($url, $this->webkit, $params);

        $this->syncKey = $dic['SyncKey'];
        $this->myself = $dic['User'];
        # synckey for synccheck
        $tempArr = [];
        if (is_array($this->syncKey['List'])) {
            foreach ($this->syncKey['List'] as $val) {
                $tempArr[] = "{$val['Key']}_{$val['Val']}";
            }
        } elseif ($first) {
            return $this->webwxinit(false);
        }
        $this->syncKeyStr = implode('|', $tempArr);

        #处理群用户
        if (!empty($dic['ChatSet'])) {
            $chatList = explode(',', $dic['ChatSet']);
            if(is_array($chatList) && !empty($chatList)){
                foreach ($chatList as $username) {
                    #群组
                    if (strpos($username, '@@') !== false) $this->group_users_sync[$username]['UserName'] = $username;
                }
            }

        }
        if ($dic['BaseResponse']['Ret'] == 0) CTools::_echo("初始化成功...");
        else CTools::_echo("初始化失败...");

    }


    /**
     * 标记消息已读
     * @return bool
     */
    public function webwxstatusnotify()
    {
        $url = sprintf($this->sessionKeys['base_url_prefix'] . '/webwxstatusnotify?lang=zh_CN&pass_ticket=%s', $this->sessionKeys['passTicket']);
        $params = [
            'BaseRequest' => $this->sessionKeys['baseRequest'],
            "Code" => 3,
            "FromUserName" => $this->myself['UserName'],
            "ToUserName" => $this->myself['UserName'],
            "ClientMsgId" => time()
        ];
        $dic = CHttpWechat::curlPostJson($url, $this->webkit, $params);
        CTools::_echo("消息已读发送...");
        return $dic['BaseResponse']['Ret'] == 0;
    }


    /**
     * 获取通讯录列表，此时获取到的群聊里面是没有用户的
     * @return bool
     */
    public function gettxlMembers($seq = 0)
    {

        $url = sprintf($this->sessionKeys['base_url_prefix'] . '/webwxgetcontact?pass_ticket=%s&skey=%s&r=%s&seq=%s',
            $this->sessionKeys['passTicket'], $this->sessionKeys['Skey'], time(), $seq);
        $dic = CHttpWechat::curlPostJson($url, $this->webkit);

        if (is_array($dic['MemberList']) && !empty($dic['MemberList'])) {
            foreach ($dic['MemberList'] as $key => $user) {
                #群组
                if (strpos($user['UserName'], '@@') !== false) {
                    $this->group_users_sync[$user['UserName']] = $user['UserName'];
                    #增加映射关系(群组和用户)
                    $this->usernameMapPinyinList[$user['PYQuanPin']] = $user['UserName'];
                }elseif (strpos($user['UserName'], '@') !== false) {
                    #普通用户 可能包含自己
                    $this->member_users[$user['UserName']] = $user;
                    #增加映射关系(群组和用户)
                    $this->usernameMapPinyinList[$user['PYQuanPin']] = $user['UserName'];
                }elseif(in_array($user['UserName'], self::systemUsers())){
                    #系统用户
                    $this->system_users[$user['UserName']] = $user;
                }elseif (($user['VerifyFlag'] & 8) != 0) {
                    #公众号
                    $this->public_users[$user['UserName']] = $user;
                }

            }

        } else {
            if (isset($dic['Seq']) && $dic['Seq'] != 0)
                $this->gettxlMembers($dic['Seq']);
        }
    }


    /**
     * 获取会话列表/更新群组信息和群组用户信息
     * @return bool
     */
    public function gethhMembers()
    {
        $url = sprintf($this->sessionKeys['base_url_prefix'] . '/webwxbatchgetcontact?type=ex&r=%s&pass_ticket=%s', time(), $this->sessionKeys['passTicket']);
        $list = [];
        if (empty($this->group_users_sync)) return;

        foreach ($this->group_users_sync as $key => $value) {
            # code...
            $list[] = ["UserName" => $key, "EncryChatRoomId" => ""];
        }
        $params = [
            'BaseRequest' => $this->sessionKeys['baseRequest'],
            "Count" => count($this->group_users_sync),
            "List" => $list
        ];
        $dic = CHttpWechat::curlPostJson($url, $this->webkit, $params);
        # blabla ...
        $contactList = $dic['ContactList'];

        if (empty($dic['ContactList'])) {
            CTools::_echo("会话更新失败...");
            return;
        }

        if (is_array($contactList) && !empty($contactList)) {
            foreach ($contactList as $key => $contact) {
                #同步群
                if (strpos($contact['UserName'], '@@') !== false) {
                    $this->group_users[$contact['UserName']] = $contact;
                } elseif (strpos($contact['UserName'], '@') !== false) {
                    #同步用户
                    $this->member_users[$contact['UserName']] = $contact;
                }
                $this->usernameMapPinyinList[$contact['PYQuanPin']] = $contact['UserName'];
            }
        }


        return;
    }


    /**
     * 获取用户信息  此处需要优化，可以改成批量
     * @param $username
     * @param int $type 1个人 2群用户
     * $group_user 群用户名
     * @return bool
     */
    public function gethUserInfo(array $user)
    {
        if (in_array($user['UserName'], $this->usernameMapPinyinList)) {
            if (!empty($user['MemberUserName'])) {
                #群用户
                foreach ($this->group_users[$user['UserName']]['MemberList'] as $member) {
                    if ($member['UserName'] == $user['MemberUserName']) return $member;
                }
            } else {
                #个人用户
                return $this->member_users[$user['UserName']];
            }
        }


        #未找到情况下更新
        $this->group_users_sync = [];
        $this->group_users_sync[$user['UserName']] = $user['UserName'];
        $this->gethhMembers();
        $this->gethUserInfo($user);

    }

    public static function systemUsers()
    {
        return ['newsapp', 'fmessage', 'filehelper', 'weibo', 'qqmail',
            'fmessage', 'tmessage', 'qmessage', 'qqsync', 'floatbottle', 'lbsapp', 'shakeapp',
            'medianote', 'qqfriend', 'readerapp', 'blogapp', 'facebookapp', 'masssendapp',
            'meishiapp', 'feedsapp', 'voip', 'blogappweixin', 'weixin', 'brandsessionholder',
            'weixinreminder', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'officialaccounts',
            'notification_messages', 'wxid_novlwrv3lqwv11', 'gh_22b87fa7cb3c', 'wxitil',
            'userexperience_alarm', 'notification_messages'
        ];
    }


    /**
     * 定时拉取动态
     * @return array
     */
    private function _syncCheck()
    {
        $params = [
            'r' => time(),
            'sid' => $this->sessionKeys['Sid'],
            'uin' => $this->sessionKeys['Uin'],
            'skey' => $this->sessionKeys['Skey'],
            'deviceid' => $this->sessionKeys['deviceID'],
            'synckey' => $this->syncKeyStr,
            '_' => time(),
        ];
        $url = $this->sessionKeys['synccheck_url'] . '/synccheck?' . http_build_query($params);
        $data = CHttpWechat::curlGet($url, $this->webkit);
        if (preg_match('/window.synccheck={retcode:"(\d+)",selector:"(\d+)"}/', $data, $pm)) {
            list($retcode, $selector) = [$pm[1], $pm[2]];
        } else {
            list($retcode, $selector) = [-1, -1];
        }
        return [$retcode, $selector];
    }


    /**
     * 获取具体信息内容
     * @return bool|mixed
     */
    private function _webwxsync()
    {

        $url = sprintf($this->sessionKeys['base_url_prefix'] . '/webwxsync?sid=%s&skey=%s&pass_ticket=%s', $this->sessionKeys['Sid'], $this->sessionKeys['Skey'], $this->sessionKeys['passTicket']);
        $params = [
            'BaseRequest' => $this->sessionKeys['baseRequest'],
            'SyncKey' => $this->syncKey,
            'rr' => time()
        ];
        $dic = CHttpWechat::curlPostJson($url, $this->webkit, $params);

        if ($dic['BaseResponse']['Ret'] == 0) {
            $this->syncKey = $dic['SyncKey'];
            $synckeyList = [];
            if (!empty($this->syncKey['List'])) {
                foreach ($this->syncKey['List'] as $keyVal) {
                    $synckey[] = "{$keyVal['Key']}_{$keyVal['Val']}";
                }
                $this->syncKeyStr = implode('|', $synckeyList);
            }
        }
        return $dic;
    }

    /**
     * 开始监听消息
     */
    public function listenMsgMode()
    {

        CTools::_echo("监听模式");

        while (true) {
            $lastCheckTime = time();
            list($retcode, $selector) = $this->_syncCheck();
            if (!($retcode == 0 && $selector == 7)) {
                CTools::_echo("监听结果:retcode(" . $retcode . ") selector(" . $selector . ")");
            }

            if (in_array($retcode, ['1100', '1101'])) {
                CTools::_echo("你在其他地方登录了 WEB 版微信或者在手机上登出了微信，债见...");
                break;
            } elseif ($retcode == '0') {
                if ($selector != '0') {
                    #获取消息列表
                    $r = $this->_webwxsync();
                    #处理消息
                    if (!empty($r['AddMsgCount'])) {
                        $msgObjFactory = new MessageFactory($this);
                        $msgObjFactory->message->handleMsg($r);
                    }
                }
            }

            //超过5秒才拉取
            $listenTime = time() - $lastCheckTime;
            if ($listenTime <= 5) sleep(1);

        }
    }


    private function _clearCookie($file)
    {
        if (file_exists($file)) unlink($file);
    }

    private function _syncSession($file)
    {

        if (file_exists($file)) unlink($file);
    }

    public function showQRCodeImg()
    {
        $url = 'https://login.weixin.qq.com/qrcode/' . $this->wechat_uuid;

        $data = file_get_contents($url);
        file_put_contents(\Yii::$app->basePath . "/runtime/qrcode.jpg", $data);
        system(\Yii::$app->basePath . "/runtime/qrcode.jpg");

//        $this->_saveFile('qrcode.jpg', $data, '_showQRCodeImg');
        //os.startfile(QRCODE_PATH)
        //T命令行显示
//        $this->cmdqrcode("https://login.weixin.qq.com/l/".$this->weuuid);
    }

    public function saveUser($list){

    }


}

